# 大合成
import tkinter as tk
from tkinter import ttk, scrolledtext, messagebox
import json
import threading
import queue
import random  # 用于战斗计算的随机性
import time  # 用于可能的延迟

# 腾讯云API相关导入 (保持不变)
import tencentcloud.common.exception.tencent_cloud_sdk_exception as exce
from tencentcloud.common.profile.http_profile import HttpProfile
from tencentcloud.common.profile.client_profile import ClientProfile
from tencentcloud.common.credential import Credential
from tencentcloud.hunyuan.v20230901 import hunyuan_client, models


# --- 角色数据类 ---
class Character:
    def __init__(self, name, stats_dict, team_name):
        self.name = name
        self.team = team_name

        self.max_hp = int(stats_dict.get("HP", 100))
        self.current_hp = int(stats_dict.get("current_hp", self.max_hp))
        self.base_atk = int(stats_dict.get("ATK", 10))
        self.base_defe = int(stats_dict.get("DEF", 5))
        self.base_spd = int(stats_dict.get("SPD", 5))
        self.base_spi = int(stats_dict.get("SPI", 10))

        self.skills = stats_dict.get("skills", [])
        self.status_effects = stats_dict.get("status_effects", [])

    @property
    def atk(self):
        return self._get_modified_stat("ATK", self.base_atk)

    @property
    def defe(self):
        return self._get_modified_stat("DEF", self.base_defe)

    @property
    def spd(self):
        return self._get_modified_stat("SPD", self.base_spd)

    @property
    def spi(self):
        return self._get_modified_stat("SPI", self.base_spi)

    def _get_modified_stat(self, stat_name_key, base_value):
        modifier_percentage = 0.0
        for effect in self.status_effects:
            changes = effect.get("stat_changes", {})
            if stat_name_key in changes:
                modifier_percentage += changes[stat_name_key]
        final_value = base_value * (1 + modifier_percentage)
        return max(1, int(final_value))

    def is_defeated(self):
        return self.current_hp <= 0

    def apply_status_effect(self, effect_to_apply):
        existing_effect_idx = -1
        for i, ef in enumerate(self.status_effects):
            if ef.get("source_skill") == effect_to_apply.get("source_skill") and \
                    ef.get("type") == effect_to_apply.get("type") and \
                    ef.get("stat_changes") == effect_to_apply.get("stat_changes"):
                existing_effect_idx = i
                break

        if existing_effect_idx != -1:
            self.status_effects[existing_effect_idx]["duration"] = max(
                self.status_effects[existing_effect_idx].get("duration", 0),
                effect_to_apply.get("duration", 0)
            )
        else:
            self.status_effects.append(effect_to_apply)

    def tick_status_effects(self):
        """回合结束时处理状态效果的持续时间，返回描述过期效果的日志字符串列表"""
        active_effects = []
        expired_log_entries = []
        for effect in self.status_effects:
            effect["duration"] = effect.get("duration", 1) - 1
            if effect["duration"] > 0:
                active_effects.append(effect)
            else:
                effect_name_part = f"来自“{effect.get('source_skill', '未知技能')}”的" if effect.get(
                    'source_skill') else ""
                stat_change_desc = ""
                if effect.get("stat_changes"):
                    changes_desc_list = []
                    for stat, val in effect.get("stat_changes").items():
                        verb = "提升" if val > 0 else "降低"
                        changes_desc_list.append(f"{stat}{verb}{abs(val * 100):.0f}%")
                    stat_change_desc = f"({', '.join(changes_desc_list)})"

                # 构造更自然的句子
                log_entry = f"{self.name} 身上 {effect_name_part}{effect.get('type', '效果')} {stat_change_desc} 已经结束。"
                expired_log_entries.append(log_entry)
        self.status_effects = active_effects
        return expired_log_entries

    def __str__(self):
        return (f"{self.name} (HP: {self.current_hp}/{self.max_hp}, "
                f"ATK:{self.atk}, DEF:{self.defe}, SPD:{self.spd}, SPI:{self.spi}, "
                f"队伍: {self.team})")


# --- 主应用类 ---
class TextBattleArenaApp:
    def __init__(self, root):
        self.root = root
        self.root.title("历史讨论群全武行")
        self.root.geometry("700x820")  # 界面稍宽，以容纳更多战斗日志

        self.style = ttk.Style()
        self.style.configure("Vertical.TScrollbar",
                             troughcolor="#EDEDED", gripcount=0, arrowsize=12,
                             background="#C0C0C0", darkcolor="#EDEDED", lightcolor="#EDEDED"
                             )

        self.role_colors = {
            "老张": {"bg": "#E8F5E9", "fg": "black", "side": "left", "font": ("Microsoft YaHei", 11)},
            "阿兰": {"bg": "#FFF3E0", "fg": "black", "side": "left", "font": ("Microsoft YaHei", 11)},
            "阿阳": {"bg": "#E3F2FD", "fg": "black", "side": "left", "font": ("Microsoft YaHei", 11)},
            "肯子": {"bg": "#FCE4EC", "fg": "black", "side": "left", "font": ("Microsoft YaHei", 11)},
            "陈飞": {"bg": "#E1BEE7", "fg": "black", "side": "left", "font": ("Microsoft YaHei", 11)},  # 新增陈飞的样式
            "东哥": {"bg": "#D7CCC8", "fg": "black", "side": "left", "font": ("Microsoft YaHei", 11)},  # 新增东哥的样式
            "小黄": {"bg": "#BBDEFB", "fg": "black", "side": "left", "font": ("Microsoft YaHei", 11)},  # 新增小黄的样式
            "战场日志": {"bg": "#4A4A4A", "fg": "#E0E0E0", "side": "left", "font": ("Microsoft YaHei", 11)},
            # 移除斜体, 增大字体
            "系统": {"bg": "#BDBDBD", "fg": "black", "side": "center", "font": ("Microsoft YaHei", 10)},
            "你": {"bg": "#a3cf62", "fg": "white", "side": "right", "font": ("Microsoft YaHei", 11)}
        }

        self.create_widgets()

        self.game_phase = "argument"
        self.argument_rounds_done = 0
        self.max_argument_rounds = 2  # 减少争吵轮数，更快进入战斗

        self.battle_characters = {}
        self.battle_teams = {}
        self.battle_turn_order = []
        self.current_attacker_idx = 0

        self.response_queue = queue.Queue()
        self.root.after(100, self.process_response_queue)
        self.is_responding = False

        # --- 系统提示保持不变 ---
        self.argument_system_prompt2 = '''模拟一场由用户输入引发的激烈争吵。请严格按照以下规则模拟多人争吵对话。
        你不要答复我，而是按照需求直接执行模拟并输出:
        1. 格式必须为"角色名: 内容"(中文冒号),每个角色独立一行,禁止嵌套(如"老张: 阿兰: xxx")
        2. 每次响应只生成1轮对话(4-7条发言)
        3. 每条发言控制在60字内
        4. 确保7个角色都参与(老张、阿兰、阿阳、肯子、陈飞、东哥、小黄)

        角色设定和口头禅:
        【老张】发言时，请以 "老张：" 开头。逆反/挑衅/历史虚无主义/用语古怪不着边际
        口头禅: '孤勇者''salabrate''你们连这都相信?'
        【阿兰】发言时，请以 "阿兰：" 开头。和事佬/三国足球/妹子
        口头禅: '哦?''哈哈''今晚有无'
        【阿阳】发言时，请以 "阿阳：" 开头。极客/时政经济/调侃老张/学识渊博
        口头禅: '逆天''火星救援''有点意思'
        【肯子】发言时，请以 "肯子：" 开头。民族主义/历史/军舰/极端者/非常爱国
        口头禅: '死啦死啦滴''有一说一'
        【陈飞】他发言时，请以 "陈飞：" 开头。历史学者/肯子同事/澳洲留学中
        【东哥】发言时，请以 "东哥：" 开头。温和派/阿阳朋友
        【小黄】发言时，请以 "小黄：" 开头。军事迷/银行从业

        当前争吵主题: [用户输入主题]

        示例正确格式:
        老张: 孤勇者又来谈爱国? 笑死salabrate
        阿兰: 哈哈,今晚有无看球赛啊?
        阿阳: 逆天!老张你这火星思维该维修了
        肯子: 有一说一,不爱国就滚出中国!
        东哥: 大家冷静点...
        小黄: 从军事史角度看...
        陈飞: 根据历史记载...'''

        self.argument_system_prompt = '''
        模拟一场由用户输入引发的激烈争吵。角色们会围绕此话题迅速爆发激烈争吵，观点鲜明，火药味十足。
        请严格按照以下规则模拟多人争吵对话:
        1. 格式必须为"角色名: 内容"(中文冒号),每个角色独立一行,禁止嵌套(如"老张: 阿兰: xxx")
        2. 每次响应只生成1轮对话(10-20条发言)
        3. 每条发言控制在60字内
        4. 确保7个角色都参与(老张、阿兰、阿阳、肯子、陈飞、东哥、小黄) 每个角色的单次回答不能太长，尽量简短限制在60字以内！角色们必须多轮互动，每个角色人设和口头禅不要混淆。
        每个角色（老张、阿兰、阿阳、肯子、陈飞、东哥、小黄）都要至少说一句话。
        输出格式为：角色名：内容。绝对要避免人物出现2次的输出，禁止嵌套(如"老张: 阿兰: xxx")。

        正确输出格式：
        老张：哟，这不是个好好的人嘛，今天怎么有空来跟我瞎聊了？孤勇者？

        阿兰：哈哈，今晚有无什么好玩的事情呢？老张，你最近过得怎么样？

        阿阳：老张，你这话说得有点意思啊，孤勇者？你是在说你自己吗？

        肯子：哼，你们这些人都太闲了，今天有什么值得讨论的历史话题吗？

        老张：历史？你们连这都相信？历史虚无主义者就是不一样，看看现在的社会现象就知道了。

        阿兰： 哦？老张，你这观点有点极端啊，历史还是有很多值得我们学习的。

        阿阳：逆天啊，老张，你这历史虚无主义者的称号可不是白叫的，你看看现在社会的发展，历史的作用还是很大的。

        小黄：东哥说得对，就像二战军备发展史，技术演进是有迹可循的。

        陈飞：肯子，甲午北洋水师弹药掺沙数据是日本防卫省公开的，别造谣。


        角色设定：
        老张： 他发言时，请以 "老张：" 开头。说话比较逆反，有时具有挑衅，用语古怪不着边际，特别喜欢答非所问。历史虚无主义者、反对一切传统的观点，不喜欢中华文化喜欢东南亚文化，反对民族主义观点，喜欢下套套出群友观点后反驳。口头禅：'还不快跪' '孤勇者''你们这群上海瘪三''无聊' 'salabrate''你们连这都相信？''不错。''这些人我不理解''耽误我这么多年'。
        阿兰：他发言时，请以 "阿兰：" 开头。澳洲曾经留学，为人热情随和，爱好三国、足球相关话题，喜欢妹子的相关话题。在争吵中可能试图和稀泥。口头禅'哦？'“哈哈”“今晚有无”“笑死”。
        阿阳：他发言时，请以 "阿阳：" 开头。极客思维，爱好时政经济相关话题，知识面非常宽广，经常调侃老张的胡言乱语，会夸张模仿老张胡言乱语，经常质疑老张的观点。口头禅“牛批”“逆天”“老张火星救援”“有点意思”，“一眼丁真”
        肯子：他发言时，请以 "肯子：" 开头。家境富裕，律师，极端的民族主义、爱国者，爱好历史相关话题，军舰爱好者，说话非常极端，极端讨厌easy girl的现象，经常带着批判的语气批评社会现象，但观点往往没有深度或者缺乏经济常识。口头禅“死啦死啦滴”“木有”“偷着乐”“有一说一”'册那'“笑死我”。
        陈飞：他发言时，请以 "陈飞：" 开头。肯子的同事、朋友，历史知识渊博，现在在澳洲留学。
        东哥：他发言时，请以 "东哥：" 开头。阿阳的好朋友，肯子、老张的高中同学。说话温和。
        小黄：他发言时，请以 "小黄：" 开头。阿阳的前同事，军事发烧友，银行从业人员。 说话温和。       




        '''
        self.chat_history = [{"Role": "system", "Content": self.argument_system_prompt}]

        self.char_gen_system_prompt = """
        基于以上对话历史（尤其是角色们的观点和激烈程度），请为上述角色生成战斗属性和2个符合其性格的独特技能。
        同时，根据他们在争论中的立场和关系，将他们分成两个对立的队伍。

        输出必须是严格的JSON格式，包含 "teams" 和 "characters" 两个主键。

        属性要求：
        - HP (生命值): 整数，范围 80-120
        - ATK (攻击力): 整数，范围 10-20
        - DEF (防御力): 整数，范围 5-15
        - SPD (速度): 整数，范围 1-10 (决定行动顺序)
        - SPI (精神力): 整数，范围 10-20 (可能影响特殊技能效果)
        - team: 字符串，指明角色所属队伍的键名 (例如 "team1" 或 "team2")
        - current_hp: 整数，初始等于HP
        - status_effects: 空列表 []

        技能要求 (每个角色2个技能，放在 "skills" 列表中，每个技能是一个对象):
        - name: 字符串，技能名称 (例如 "孤勇者", "三国空城计","法治精神")
        - description: 字符串，技能的简短描述
        - type: 字符串，技能类型 ("damage", "buff", "debuff", "heal")
        - target: 字符串，技能目标 ("single_enemy", "all_enemies", "self", "single_ally", "all_allies")
        - accuracy: 整数，命中率 (0-100)
        - power: 整数，技能威力 (用于伤害计算，伤害技能必须有此项，范围10-30)
        - (可选) stat_changes: 对象，用于buff/debuff，键为属性名(如"ATK", "DEF", "SPI", "SPD")，值为变化百分比(如0.2表示增加20%，-0.1表示减少10%)。示例: {"ATK": 0.2, "DEF": -0.1}
        - (可选) duration: 整数，buff/debuff的持续回合数 (例如 2 或 3)
        - (可选) effect_description: 字符串，描述技能的特殊效果，如“使目标混乱1回合”。（此项让LLM自由发挥，Python端可暂不完全实现其逻辑，主要用于播报）
        - (可选) source_skill: 字符串，技能名称，用于状态效果溯源。LLM生成时应与技能 "name" 一致。

        JSON格式示例:
        {
          "teams": {
            "team1": ["老张", "阿阳", "东哥","小黄"],
            "team2": ["阿兰", "肯子","陈飞"]
          },
          "characters": {
            "老张": {
              "HP": 100, "ATK": 15, "DEF": 10, "SPD": 5, "SPI": 18, "team": "team1", "current_hp": 100, "status_effects": [],
              "skills": [
                {"name": "答非所问", "source_skill": "答非所问", "description": "出其不意的言语攻击", "type": "damage", "target": "single_enemy", "accuracy": 90, "power": 25, "effect_description": "基于精神力造成额外伤害"},
                {"name": "历史虚无", "source_skill": "历史虚无", "description": "散播虚无主义思想，削弱敌人", "type": "debuff", "target": "all_enemies", "accuracy": 80, "stat_changes": {"DEF": -0.15, "SPI": -0.1}, "duration": 2, "effect_description": "降低全体敌人防御和精神"}
              ]
            },
            "阿兰": {
              "HP": 90, "ATK": 12, "DEF": 8, "SPD": 7, "SPI": 15, "team": "team2", "current_hp": 90, "status_effects": [],
              "skills": [
                {"name": "三国空城计", "source_skill": "三国空城计", "description": "摆出姿态迷惑对手", "type": "buff", "target": "self", "accuracy": 100, "stat_changes": {"DEF": 0.3, "SPD": 0.1}, "duration": 3, "effect_description": "大幅提升自身防御和少许速度"},
                {"name": "今晚有无?", "source_skill": "今晚有无?", "description": "用无关话题干扰对手", "type": "debuff", "target": "single_enemy", "accuracy": 75, "effect_description": "有几率使单体敌人混乱1回合（跳过行动）"}
              ]
            }
            // ... 阿阳、肯子等其他角色的数据 ...
          }
        }
        """
        self.init_client()

    def init_client(self):
        try:
            obfuscated_secret_id = '加密密钥id'
            obfuscated_secret_key = '加密密钥'
            SECRET_ID = self.get_decrypted_key(obfuscated_secret_id)
            SECRET_KEY = self.get_decrypted_key(obfuscated_secret_key)

            # --- 调试：打印解密后的密钥（确保不要泄露真实密钥） ---
            # print(f"DEBUG: Decrypted SECRET_ID (last 4 chars): ...{SECRET_ID[-4:]}")
            # print(f"DEBUG: Decrypted SECRET_KEY (last 4 chars): ...{SECRET_KEY[-4:]}")
            # --- 调试结束 ---

            credential = Credential(SECRET_ID, SECRET_KEY)
            http_profile = HttpProfile()
            http_profile.req_method = "POST"
            http_profile.req_timeout = 60  # 增加超时时间以防网络慢
            http_profile.endpoint = "hunyuan.tencentcloudapi.com"
            client_profile = ClientProfile()
            client_profile.http_profile = http_profile
            self.client = hunyuan_client.HunyuanClient(credential, "", client_profile)  # region 通常对 hunyuan 非必须，可以为空
            print("DEBUG: API Client initialized successfully.")  # 调试信息
        except Exception as e:
            print(f"DEBUG: API Client initialization failed: {e}")  # 调试信息
            messagebox.showerror("错误", f"初始化API客户端失败: {str(e)}")
            self.client = None  # 明确设置为None，防止后续使用

    def get_decrypted_key(self, obfuscated_key):
        key = obfuscated_key.replace('@#@', 'a').replace('$%$', 't').replace('^&^', 'Z')
        return key[::-1]

    def create_widgets(self):
        # 将根窗口背景色从深色改为淡灰色
        self.root.configure(bg="#F0F0F0")  # 例如，一个淡灰色

        # 聊天显示区域的颜色也相应调整，以匹配新的淡色主题
        self.chat_display = scrolledtext.ScrolledText(
            self.root, wrap=tk.WORD, width=70, height=35,
            bg="#FFFFFF",  # 白色背景
            fg="#333333",  # 深灰色文字
            insertbackground="#000000",  # 光标颜色
            font=("Microsoft YaHei", 11), state='disabled',
            spacing2=3, relief="solid", borderwidth=1, bd=1, highlightthickness=0
        )
        self.chat_display.pack(pady=(10, 0), padx=10, fill=tk.BOTH, expand=True)

        # --- 添加右键复制功能 (保持不变) ---
        self.chat_display_menu = tk.Menu(self.root, tearoff=0)
        self.chat_display_menu.add_command(label="复制", command=self.copy_chat_display_text)

        def show_chat_display_menu(event):
            self.chat_display_menu.tk_popup(event.x_root, event.y_root)

        self.chat_display.bind("<Button-3>", show_chat_display_menu)
        # --- 右键复制功能结束 ---

        # 角色样式的背景色可能也需要调整，以确保在淡色背景下仍然清晰
        # 例如，"战场日志" 和 "系统" 的背景色如果之前是深色，现在可能需要改成浅色或者调整文字颜色
        # 这里保持原有逻辑，但您可能需要根据新的主背景色微调 self.role_colors 中的 bg 和 fg 值
        # 特别是对于 "战场日志" 和 "系统"
        # 示例调整 (您可以根据喜好进一步修改):
        # self.role_colors["战场日志"]["bg"] = "#EAEAEA"
        # self.role_colors["战场日志"]["fg"] = "#1C1C1C"
        # self.role_colors["系统"]["bg"] = "#DCDCDC"
        # self.role_colors["系统"]["fg"] = "#000000"
        for role, style_config in self.role_colors.items():
            self.chat_display.tag_configure(
                role, background=style_config["bg"], foreground=style_config["fg"],
                lmargin1=12 if style_config["side"] == "left" else (25 if style_config["side"] == "center" else 80),
                lmargin2=12 if style_config["side"] == "left" else (25 if style_config["side"] == "center" else 80),
                rmargin=80 if style_config["side"] == "left" else (25 if style_config["side"] == "center" else 12),
                spacing3=3, wrap=tk.WORD,
                justify=tk.LEFT if style_config["side"] == "left" else (
                    tk.CENTER if style_config["side"] == "center" else tk.RIGHT),
                relief="flat", font=style_config.get("font", ("Microsoft YaHei", 11))
            )

        # 页脚区域颜色调整
        self.footer_frame = tk.Frame(self.root, bg="#E0E0E0", height=20, relief="flat",  # 更浅的灰色
                                     highlightthickness=1, highlightbackground="#CCCCCC")  # 边框颜色
        self.footer_frame.pack(fill=tk.X, padx=8, pady=(5, 0), side=tk.BOTTOM)

        self.footer_label = tk.Label(
            self.footer_frame, text="作者：luke（伊玛目的门徒）  联系邮箱：luul11@163.com  版本号：V1.0",
            bg="#E0E0E0",  # 匹配父框架背景
            fg="#333333",  # 深色文字
            font=("Microsoft YaHei", 10),
            anchor='center'
        )
        self.footer_label.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)

        # 您可以从这里开始替换或检查
        # 用户输入区域颜色调整 (假设背景等已按之前建议修改)
        self.user_input_frame = tk.Frame(self.root, bg="#E0E0E0", height=60, relief="flat",
                                         highlightthickness=1, highlightbackground="#CCCCCC")
        self.user_input_frame.pack(fill=tk.X, padx=8, pady=(5, 8), side=tk.BOTTOM)

        # 输入栏：保持其扩展属性
        self.input_entry = tk.Entry(
            self.user_input_frame,
            # width 属性保持移除或注释状态，以允许动态扩展
            bg="#FFFFFF",
            fg="#000000",
            insertbackground="#000000",
            font=("Microsoft YaHei", 13),
            borderwidth=1, relief="solid",
            highlightthickness=0
        )
        # input_entry 使用 expand=True 和 fill=tk.X 来占据尽可能多的宽度
        self.input_entry.pack(side=tk.LEFT, expand=True, fill=tk.X, padx=(10, 5), pady=8)  # 左侧10px，右侧5px间距
        self.input_entry.bind("<Return>", lambda event: self.handle_user_input())

        # 按钮美化: 减小按钮的水平内边距 (padx)
        self.send_button = tk.Button(
            self.user_input_frame, text="发表观点", command=self.handle_user_input,
            bg="#4CAF50",
            fg="#FFFFFF",
            font=("Microsoft YaHei", 12, "bold"),
            relief="flat",
            borderwidth=0,
            activebackground="#45a049",
            activeforeground="#FFFFFF",
            cursor="hand2",
            padx=10,  # 将按钮的水平内边距从 15 减小到 10，使其更窄
            pady=8
        )
        self.send_button.pack(side=tk.RIGHT, padx=(0, 10), pady=8)  # 按钮右侧保留10px外边距

    def copy_chat_display_text(self):
        """复制 ScrolledText 中选中的文本"""
        try:
            selected_text = self.chat_display.get(tk.SEL_FIRST, tk.SEL_LAST)
            self.root.clipboard_clear()  # 清空剪贴板
            self.root.clipboard_append(selected_text)  # 添加到剪贴板
            print("DEBUG: Text copied to clipboard.")
        except tk.TclError:
            print("DEBUG: No text selected or error copying.")  # 没有选中文本时会引发 TclError

    def display_message(self, sender, message, add_newline=True):
        """在聊天窗口显示消息，适配战斗日志"""
        try:
            self.chat_display.config(state='normal')
            tag_to_use = sender
            if sender not in self.role_colors:
                tag_to_use = "战场日志"

            prefix = ""
            is_battle_log_entry = (sender == "战场日志")  # 标记是否为战斗日志条目

            if sender in self.role_colors and sender not in ["战场日志", "系统", "你"]:
                prefix = f"{sender}：\n  "  # 角色对话保持原有格式
            elif is_battle_log_entry:
                # 战场日志条目不再使用特殊符号作为前缀，而是依赖于内容本身的格式
                # prefix = f"๏ " # 移除这个，让内容自己控制
                pass
            elif sender == "你":
                prefix = f"你： "
            elif sender == "系统":
                prefix = f"[系统]： "

            full_message = f"{prefix}{message}"

            if add_newline:  # add_newline 控制的是这条消息块之后的整体大换行
                if is_battle_log_entry:
                    full_message += "\n"  # 战斗日志条目之间用一个换行分隔
                else:
                    full_message += "\n\n"  # 其他消息类型用两个换行

            # 对于战斗日志，我们可能希望每条具体效果后都换行，这在生成日志时处理

            self.chat_display.insert(tk.END, full_message, tag_to_use)
            self.chat_display.see(tk.END)
            self.chat_display.config(state='disabled')
        except Exception as e:
            print(f"DEBUG: Error in display_message: {str(e)}")

    def toggle_ui_state(self, enable):
        state = tk.NORMAL if enable else tk.DISABLED
        self.send_button.config(state=state)
        self.input_entry.config(state=state if enable else 'readonly')
        if enable:
            self.send_button.config(text=self._get_button_text_for_phase())
            self.input_entry.focus()

    def _get_button_text_for_phase(self):
        if self.game_phase == "argument":
            return "发表观点"
        elif self.game_phase == "char_setup_request":
            return "生成中..."
        elif self.game_phase == "char_setup_done":
            return "开始战斗！"
        elif self.game_phase == "battle":
            return "处理中..."  # 战斗中按钮通常禁用或显示处理中
        elif self.game_phase == "battle_over":
            return "重新开始"
        return "发送/继续"

    def process_response_queue(self):
        try:
            while True:
                # 第一个元素是发送者/标签，第二个是内容，第三个可选的是是否添加默认换行
                item = self.response_queue.get_nowait()
                sender, content = item[0], item[1]
                add_newline = item[2] if len(item) > 2 else True

                if sender == "SYSTEM_PHASE_UPDATE":
                    new_phase = content
                    if new_phase == "char_setup_done":
                        self.game_phase = "char_setup_done"
                        self.display_message("系统", "角色和队伍配置完成！点击“开始战斗！”按钮。")
                    elif new_phase == "argument":
                        self.game_phase = "argument"
                    elif new_phase == "battle_over":
                        self.game_phase = "battle_over"
                        self.display_message("系统", "战斗已结束。点击“重新开始”进行新一轮游戏。")

                    self.toggle_ui_state(True)  # 阶段更新后通常允许用户操作
                else:
                    self.display_message(sender, content, add_newline)
                self.response_queue.task_done()
        except queue.Empty:
            pass
        except Exception as e:
            print(f"DEBUG: Error in process_response_queue: {str(e)}")
        finally:
            self.root.after(100, self.process_response_queue)

    def handle_user_input(self):
        if not self.client:
            messagebox.showerror("错误", "API客户端未初始化。")
            return
        if self.is_responding:
            messagebox.showwarning("请稍候", "正在等待AI响应或战斗计算...")
            return

        user_text = self.input_entry.get().strip()
        self.input_entry.delete(0, tk.END)

        if self.game_phase == "argument":
            if not user_text and self.argument_rounds_done == 0:
                messagebox.showinfo("提示", "请输入一个引发争吵的话题开始。")
                return

            self.is_responding = True
            self.toggle_ui_state(False)
            if user_text:
                self.display_message("你", user_text)
                self.chat_history.append({"Role": "user", "Content": user_text})
            else:  # 用户直接回车，示意继续争吵或进入下一阶段
                if self.argument_rounds_done >= self.max_argument_rounds:
                    self.game_phase = "char_setup_request"  # 强制进入角色生成
                    self.prompt_for_char_generation()  # 这里直接调用，因为is_responding=True会阻止重复
                    return  # 不再请求LLM争吵
                else:
                    self.display_message("你", "(示意继续争吵...)")

            threading.Thread(target=self.handle_argument_stream_llm, daemon=True).start()

        elif self.game_phase == "char_setup_request":
            # 此阶段通常是自动触发或由上一阶段转换而来，按钮点击也可能到这里
            self.request_character_generation_llm()

        elif self.game_phase == "char_setup_done":
            self.start_battle_proper()

        elif self.game_phase == "battle":
            # 战斗是自动进行的，用户输入此时无效，按钮应禁用或显示“处理中”
            self.display_message("系统", "战斗正在自动进行中...")

        elif self.game_phase == "battle_over":
            self.reset_game()

    def reset_game(self):
        self.game_phase = "argument"
        self.argument_rounds_done = 0
        self.battle_characters.clear()
        self.battle_teams.clear()
        self.battle_turn_order = []
        self.current_attacker_idx = 0
        self.chat_history = [{"Role": "system", "Content": self.argument_system_prompt}]
        self.chat_display.config(state='normal')
        self.chat_display.delete(1.0, tk.END)
        self.chat_display.config(state='disabled')
        self.display_message("系统", "游戏已重置。请输入新的话题开始。")
        self.toggle_ui_state(True)

    def handle_argument_stream_llm(self):
        print("DEBUG: Requesting argument stream from LLM...")
        try:
            req = models.ChatCompletionsRequest()

            history_for_api = []
            for msg_dict in self.chat_history:  # msg_dict 是一个字典，例如 {"Role": "user", "Content": "你好"}
                if msg_dict["Role"] in ["system", "user", "assistant"]:
                    message_obj = models.Message()  # 先创建 Message 实例
                    message_obj.Role = msg_dict["Role"]  # 再设置 Role 属性
                    message_obj.Content = msg_dict["Content"]  # 再设置 Content 属性
                    history_for_api.append(message_obj)

            req.Messages = history_for_api

            # req.Model = "hunyuan-standard"
            req.Model = "hunyuan-t1-latest"

            req.Stream = True
            req.Temperature = 0.75
            req.TopP = 0.9

            resp_stream = self.client.ChatCompletions(req)

            line_buffer = ""
            current_llm_speaker = ""  # 追踪LLM输出的当前说话人
            full_ai_response_for_history = ""

            for chunk_data_wrapper in resp_stream:
                if "data" not in chunk_data_wrapper: continue
                json_string_payload = chunk_data_wrapper["data"]
                if not json_string_payload or json_string_payload == "[DONE]": continue

                try:
                    chunk_data = json.loads(json_string_payload)
                    print(chunk_data)
                except json.JSONDecodeError:
                    continue

                if chunk_data.get("Error"):
                    self.response_queue.put(
                        ("系统", f"LLM API错误(争吵): {chunk_data['Error'].get('Message', '未知错误')}"))
                    break

                if chunk_data.get("Choices"):
                    delta = chunk_data["Choices"][0].get("Delta", {})
                    new_content_fragment = delta.get("Content", "")
                    if new_content_fragment:
                        full_ai_response_for_history += new_content_fragment
                        line_buffer += new_content_fragment

                        while '\n' in line_buffer:
                            line, line_buffer = line_buffer.split('\n', 1)
                            line = line.strip()
                            if line:

                                parts = line.split("：", 1) if "：" in line else line.split(":", 1)
                                if len(parts) == 2 and parts[0] in self.role_colors:
                                    current_llm_speaker = parts[0]
                                    message_content = parts[1].strip()
                                    if message_content:
                                        self.response_queue.put((current_llm_speaker, message_content))
                                elif current_llm_speaker and line:  # 无角色前缀，作为上一角色发言的延续
                                    self.response_queue.put((current_llm_speaker, line))
                                # else: # 也可以考虑作为系统消息处理
                                #     self.response_queue.put(("系统", line))

            if full_ai_response_for_history:
                self.chat_history.append({"Role": "assistant", "Content": full_ai_response_for_history.strip()})

            self.argument_rounds_done += 1

        except Exception as e:
            self.response_queue.put(("系统", f"处理争吵流时发生错误: {str(e)}"))
        finally:
            self.is_responding = False
            self.root.after(0, self.toggle_ui_state, True)
            if self.argument_rounds_done >= self.max_argument_rounds and self.game_phase == "argument":
                self.root.after(100, self.prompt_for_char_generation)

    def prompt_for_char_generation(self):
        self.game_phase = "char_setup_request"
        self.display_message("系统",
                             f"争论已进行 {self.argument_rounds_done} 轮。批判的武器始终不如武器的批判。将开始备战，生成角色属性和队伍...")
        self.send_button.config(text="生成中...")  # 按钮文本更新
        self.request_character_generation_llm()  # 自动触发

    def request_character_generation_llm(self):
        if self.is_responding: return
        self.is_responding = True
        self.toggle_ui_state(False)

        # 构建用于角色生成的消息列表
        char_gen_messages = []

        # 1. 添加系统提示
        char_gen_messages.append({"Role": "system", "Content": self.char_gen_system_prompt})

        # 2. 添加相关的争吵历史 (确保不包含旧的system prompt)
        valid_roles_for_history = ["user", "assistant"]
        history_for_char_gen = []
        # 从 self.chat_history 中提取对话，跳过第一个 system prompt
        for msg in self.chat_history:
            if msg["Role"] in valid_roles_for_history:
                history_for_char_gen.append(msg)

        # 取最近的 N 条对话历史，例如最后10条 (3轮对话)
        len_talks = len(history_for_char_gen)
        if len_talks >= 15:
            len_talks = 15

        char_gen_messages.extend(history_for_char_gen[-len_talks:])  # 可调整数量

        # 3. 添加一个明确的 user 指令，请求模型根据以上信息生成JSON
        #    这条消息是关键，确保 Messages 列表以 user 请求结束。
        char_gen_messages.append({
            "Role": "user",
            "Content": '''请根据以上对话历史、人设和系统提示，生成角色属性、技能和2个队伍的JSON数据。 如果两队成员数量存在差异，给人少的一队HP和防御力额外增强。               
                        角色设定：
                        老张： 他发言时，请以 "老张：" 开头。说话比较逆反，有时具有挑衅，用语古怪不着边际（天马行空），特别喜欢答非所问。历史虚无主义者、反对一切传统的观点，不喜欢中华文化喜欢东南亚文化，反对民族主义观点，喜欢下套套出群友观点后反驳。口头禅： '孤勇者'你们这群上海瘪三''salabrate''你们连这都相信？''不错。''这些人我不理解''耽误我这么多年'。
                        阿兰：他发言时，请以 "阿兰：" 开头。为人热情随和，爱好三国、足球相关话题，喜欢妹子的相关话题。在争吵中可能试图和稀泥，或者用不相干的话题打岔。口头禅'哦？'“哈哈”“今晚有无”。
                        阿阳：他发言时，请以 "阿阳：" 开头。极客思维，爱好时政经济相关话题，知识面非常宽广，经常调侃老张的胡言乱语，会夸张模仿老张胡言乱语，经常质疑老张的观点。口头禅“牛批”“逆天”“老张火星救援”“有点意思”。一般加入人少的1队。
                        肯子：他发言时，请以 "肯子：" 开头。家境富裕，强烈的民族主义者，爱好历史相关话题，军舰爱好者，说话非常极端，极端讨厌easy girl的现象，经常带着批判的语气批评社会现象，极端爱国者。口头禅“死啦死啦滴”“木有”“偷着乐”“有一说一”“笑死我”。
                        陈飞：他发言时，请以 "陈飞：" 开头。肯子的同事、朋友，历史知识渊博，现在在澳洲留学。一般和肯子一队。
                        东哥：他发言时，请以 "东哥：" 开头。阿阳的好朋友，阿阳的初中高中同学，肯子、老张的高中同学。说话温和。一般和阿阳一队
                        小黄：他发言时，请以 "小黄：" 开头。阿阳的前同事，军事发烧友，银行从业人员。 说话温和。 '''
        })

        print("DEBUG: Requesting character generation from LLM (non-stream)...")
        # 打印将要发送给API的完整消息列表，用于调试
        # print("DEBUG: Messages for char gen:", json.dumps(char_gen_messages, ensure_ascii=False, indent=2))

        threading.Thread(target=self._background_char_gen_request, args=(char_gen_messages,), daemon=True).start()

    def _background_char_gen_request(self, messages_for_llm):
        try:
            req = models.ChatCompletionsRequest()

            # --- 修正 Message 对象的创建 ---
            sdk_messages = []
            for msg_dict in messages_for_llm:  # messages_for_llm 也是一个字典列表
                message_obj = models.Message()
                message_obj.Role = msg_dict["Role"]
                message_obj.Content = msg_dict["Content"]
                sdk_messages.append(message_obj)

            req.Model = "hunyuan-standard"
            req.Messages = sdk_messages
            req.Stream = False  # 非流式获取完整JSON
            req.Temperature = 0.3  # 低温以保证JSON格式的稳定性

            resp = self.client.ChatCompletions(req)

            if resp.Choices and resp.Choices[0].Message and resp.Choices[0].Message.Content:
                json_string = resp.Choices[0].Message.Content
                print(f"DEBUG: Received JSON string for characters: {json_string[:300]}...")  # 打印部分
                self.parse_and_setup_characters(json_string)
            else:
                error_msg = "未能从API获取角色生成数据。"
                if hasattr(resp, 'Error') and resp.Error: error_msg += f" API Error: {resp.Error.Message}"
                self.response_queue.put(("系统", error_msg))
                self.response_queue.put(("SYSTEM_PHASE_UPDATE", "argument"))  # 退回争吵阶段

        except exce.TencentCloudSDKException as tc_ex:
            self.response_queue.put(("系统", f"腾讯云API错误 (角色生成): {tc_ex.get_message()}"))
            self.response_queue.put(("SYSTEM_PHASE_UPDATE", "argument"))
        except Exception as e:
            self.response_queue.put(("系统", f"解析角色数据错误: {str(e)}"))
            self.response_queue.put(("SYSTEM_PHASE_UPDATE", "argument"))
        finally:
            self.is_responding = False
            # UI状态更新由 process_response_queue 中的 SYSTEM_PHASE_UPDATE 处理

    def parse_and_setup_characters(self, json_string):
        try:
            # 尝试去除可能的代码块标记
            if json_string.strip().startswith("```json"):
                json_string = json_string.strip()[7:-3].strip()
            elif json_string.strip().startswith("```"):
                json_string = json_string.strip()[3:-3].strip()

            data = json.loads(json_string)
            self.battle_teams = data.get("teams", {})
            raw_chars_data = data.get("characters", {})

            self.battle_characters.clear()
            created_character_names = []
            for name, stats in raw_chars_data.items():
                if name in self.role_colors and name not in ["系统", "你", "战场日志"]:  # 确保是可战斗角色
                    self.battle_characters[name] = Character(name, stats, stats.get("team"))
                    created_character_names.append(name)
                    # 界面上显示角色基本信息
                    self.response_queue.put(("系统",
                                             f"角色 {name} 已加载: HP={stats['HP']}, ATK={stats['ATK']}, DEF={stats['DEF']}, SPD={stats['SPD']}, SPI={stats['SPI']}"))
                    for skill in stats.get("skills", []):
                        self.response_queue.put(("系统",
                                                 f"  └技能: {skill['name']} ({skill.get('type', '未知类型')}) - {skill['description']}",
                                                 False))  # 技能描述不加额外换行

            if not self.battle_characters or not self.battle_teams or len(created_character_names) < 4:
                self.response_queue.put(("系统", "角色或队伍数据不完整或数量不足，请重试。"))
                self.response_queue.put(("SYSTEM_PHASE_UPDATE", "argument"))
                return

            # 验证队伍成员是否都已创建
            for team_id, members in self.battle_teams.items():
                valid_members = [m for m in members if m in self.battle_characters]
                self.battle_teams[team_id] = valid_members
                self.response_queue.put(("系统", f"队伍 {team_id}: {', '.join(valid_members)}"))
                if len(valid_members) < 2:
                    self.response_queue.put(("系统", f"警告：队伍 {team_id} 成员数量不足 ({len(valid_members)}/2)。"))
                    # 可以选择在此处中断或允许继续

            self.response_queue.put(("SYSTEM_PHASE_UPDATE", "char_setup_done"))

        except json.JSONDecodeError as e:
            self.response_queue.put(("系统", f"JSON解析错误: {e}. LLM原始输出片段: {json_string[:200]}..."))
            self.response_queue.put(("SYSTEM_PHASE_UPDATE", "argument"))
        except Exception as e:
            self.response_queue.put(("系统", f"设置角色时出错: {str(e)}"))
            self.response_queue.put(("SYSTEM_PHASE_UPDATE", "argument"))

    def start_battle_proper(self):
        """准备并开始战斗"""
        self.game_phase = "battle"
        self.toggle_ui_state(False)  # 进入战斗后，禁用用户输入按钮
        self.response_queue.put(("战场日志", "战斗正式开始！\n", True))

        # --- 恢复获取 active_fighters 的逻辑 ---
        all_team_members = set()  # 使用集合避免重复，并提高查找效率
        for team_id in self.battle_teams:
            for member_name in self.battle_teams.get(team_id, []):
                all_team_members.add(member_name)

        active_fighters = []
        if not all_team_members:  # 如果没有队伍成员（例如角色生成失败或队伍分配问题）
            self.response_queue.put(("系统", "错误：队伍中没有任何角色。"))
        else:
            for char_name, char_obj in self.battle_characters.items():
                # 确保角色在队伍中，并且还活着
                if char_name in all_team_members and not char_obj.is_defeated():
                    active_fighters.append(char_obj)
        # --- 恢复结束 ---

        if len(active_fighters) < 2:
            self.response_queue.put(("系统", "参战角色不足 (少于2人)，无法开始战斗。请检查角色生成和队伍分配。"))
            self.response_queue.put(("SYSTEM_PHASE_UPDATE", "char_setup_done"))
            return

        # 按速度决定行动顺序，加入微小随机数避免速度完全相同时顺序固定
        active_fighters.sort(key=lambda c: (c.spd, random.random()), reverse=True)
        self.battle_turn_order = [char.name for char in active_fighters]
        self.current_attacker_idx = 0

        if not self.battle_turn_order:
            self.response_queue.put(("系统", "未能确定行动顺序，战斗无法开始。"))
            self.response_queue.put(("SYSTEM_PHASE_UPDATE", "char_setup_done"))
            return

        # 初始状态显示和行动顺序
        initial_statuses = ["初始战场状态："]  # 标题更清晰
        for char_name_in_order in self.battle_turn_order:  # 按照行动顺序显示
            char_obj = self.battle_characters.get(char_name_in_order)
            if char_obj:  # 确保角色对象存在
                initial_statuses.append(
                    f"  {char_obj.name} (HP: {char_obj.current_hp}/{char_obj.max_hp}, SPD: {char_obj.spd})")
        self.response_queue.put(("战场日志", "\n".join(initial_statuses), False))  # 列表内容已包含换行
        self.response_queue.put(("战场日志", "行动顺序：" + " -> ".join(self.battle_turn_order) + "\n", True))

        # 稍作延迟开始第一回合的第一个行动者提示
        first_attacker_name = self.battle_turn_order[0]
        self.root.after(1000, lambda name=first_attacker_name: self.response_queue.put(
            ("战场日志", f"\n轮到 {name} 行动...", True)
        ))
        self.root.after(2000, self.process_battle_turn)  # 再过1秒执行回合处理

    # --- 战斗逻辑核心 ---
    def process_battle_turn(self):
        """处理当前战斗回合"""
        if self.check_battle_end():
            return

        if not self.battle_turn_order:
            self.response_queue.put(("战场日志", "错误：行动顺序为空！"))
            self.response_queue.put(("SYSTEM_PHASE_UPDATE", "battle_over"))
            return

        attacker_name = self.battle_turn_order[self.current_attacker_idx]
        attacker = self.battle_characters.get(attacker_name)

        if not attacker or attacker.is_defeated():
            # self.display_message("战场日志", f"{attacker_name} 已无法行动。") # 这条日志可以省略或调整
            self.advance_turn()
            return

        # --- 优化回合开始的日志 ---
        # 不再使用 "--- XXX的回合 ---" 这种冗余信息，改为更简洁的提示
        # self.display_message("战场日志", f"\n--- {attacker.name}的回合 ({attacker.current_hp}/{attacker.max_hp} HP) ---", False)
        # 可以在AI选择行动后，直接说明谁在行动
        # ---

        chosen_skill, targets = self._ai_choose_action(attacker)

        if not chosen_skill or not targets:
            # 如果没有行动，可以发送一个简洁的日志
            self.response_queue.put(("战场日志", f"{attacker.name} 思考中...", True))  # add_newline=True 让这条单独占行
        else:
            # 在execute_skill中会详细打印行动信息
            # self.display_message("战场日志", f"{attacker.name} 准备使用技能【{chosen_skill['name']}】({chosen_skill['description']})", False)

            for target_char_obj in targets:  # 注意这里变量名，避免与python关键字 target 冲突
                if target_char_obj.is_defeated():
                    self.response_queue.put(("战场日志", f"但 {target_char_obj.name} 已经倒下了！", True))
                    continue

                # execute_skill 现在应该返回一个包含多条日志的列表
                # 每条日志都已经预格式化好，包含必要的换行
                log_segments = self.execute_skill(attacker, target_char_obj, chosen_skill)
                for segment in log_segments:
                    self.response_queue.put(("战场日志", segment, False))  # False表示这些日志段内部自己控制换行

        # 处理攻击者回合结束时的状态效果
        attacker_status_ticks = attacker.tick_status_effects()  # 返回日志列表
        if attacker_status_ticks:
            for tick_log in attacker_status_ticks:
                self.response_queue.put(("战场日志", tick_log, False))

        if self.check_battle_end():
            return

        self.advance_turn()

    def _ai_choose_action(self, attacker: Character):
        """AI选择行动：有概率使用普通攻击，否则在可用技能中选择。"""

        basic_attack_verbs = ["揍了", "踢了", "殴打了", "痛扁了", "猛击了", "挥拳攻击了"]
        use_basic_attack_probability = 1 / 3

        chosen_action = None
        targets = []

        if random.random() < use_basic_attack_probability:
            chosen_action = {
                "name": "普通攻击",
                "type": "basic_attack",
                "description": f"{random.choice(basic_attack_verbs)}对手",
                "target": "single_enemy",
                "accuracy": 95
            }
            print(f"DEBUG: {attacker.name} 决定使用普通攻击。")
        else:
            available_skills = [s for s in attacker.skills if s.get("type")]
            if not available_skills:
                chosen_action = {
                    "name": "普通攻击", "type": "basic_attack",
                    "description": f"{random.choice(basic_attack_verbs)}对手",
                    "target": "single_enemy", "accuracy": 95
                }
                print(f"DEBUG: {attacker.name} 没有可用技能，改为普通攻击。")
            else:
                chosen_action = random.choice(available_skills)
                print(f"DEBUG: {attacker.name} 决定使用技能: {chosen_action.get('name')}")

        if not chosen_action:
            return None, None

        action_target_type = chosen_action.get("target")

        if action_target_type == "self":
            targets = [attacker]
        elif action_target_type in ["single_enemy", "all_enemies"]:
            # --- 修正这里的列表推导式 ---
            opponent_team_members = [
                char_obj for name, char_obj in self.battle_characters.items()  # 使用 char_obj
                if char_obj.team != attacker.team and not char_obj.is_defeated()
            ]
            # --- 修正结束 ---
            if not opponent_team_members:
                if chosen_action["type"] == "basic_attack" or action_target_type == "single_enemy":
                    print(f"DEBUG: {attacker.name} 找不到攻击目标！")
                    return None, None
                else:
                    targets = []

            elif action_target_type == "single_enemy":
                targets = [random.choice(opponent_team_members)]
            else:
                targets = opponent_team_members

        elif action_target_type in ["single_ally", "all_allies"]:
            # --- 修正这里的列表推导式 ---
            ally_team_members = [
                char_obj for name, char_obj in self.battle_characters.items()  # 使用 char_obj
                if char_obj.team == attacker.team and not char_obj.is_defeated()
            ]
            # --- 修正结束 ---
            if not ally_team_members:
                if chosen_action.get("type") == "buff" and chosen_action.get("can_target_self_if_no_ally", True):
                    targets = [attacker]
                else:
                    print(f"DEBUG: {attacker.name} 找不到友方目标！")
                    return None, None

            elif action_target_type == "single_ally":
                other_allies = [ally for ally in ally_team_members if ally.name != attacker.name]
                if other_allies:
                    targets = [random.choice(other_allies)]
                elif chosen_action.get("can_target_self_if_no_ally", True):
                    targets = [attacker]
                else:
                    print(f"DEBUG: {attacker.name} 找不到其他友方目标！")
                    return None, None
            else:
                targets = ally_team_members

        return chosen_action, targets

    def execute_skill(self, attacker: Character, target_char: Character, skill_or_action: dict):
        """执行技能或普通攻击计算，返回格式化好的战斗日志字符串列表"""
        log_entries = []

        action_name = skill_or_action.get("name", "未知行动")
        action_type = skill_or_action.get("type", "unknown")

        # --- 日志头部 ---
        if action_type == "basic_attack":
            # 普通攻击的描述已经在 skill_or_action['description'] 中
            action_header = f"【{attacker.name} 】({attacker.current_hp} HP) {skill_or_action['description']} 【{target_char.name}】 ({target_char.current_hp} HP)！"
        else:  # 是一个技能
            action_header = f"【{attacker.name}】 ({attacker.current_hp} HP) 对 【{target_char.name}】 ({target_char.current_hp} HP) 使用【{action_name}】："
        log_entries.append(action_header)

        # --- 命中判定 ---
        is_hit = random.randint(1, 100) <= skill_or_action.get("accuracy", 90)  # 普通攻击也用accuracy
        if not is_hit:
            log_entries.append("  ↳ 未命中！(MISS)")
            return log_entries

        # --- 根据行动类型处理效果 ---
        if action_type == "basic_attack":
            # 普通攻击伤害计算: (攻击方ATK - 防御方DEF) * 随机浮动 (0.9 - 1.1)
            # 也可以给普通攻击一个小的固定威力，或者完全基于ATK
            damage = attacker.atk - target_char.defe + 10
            damage = max(1, int(damage * random.uniform(0.9, 1.1)))

            target_char.current_hp -= damage
            log_entries.append(
                f"  ↳ 造成 {damage} 点伤害！{target_char.name} 剩余HP: {target_char.current_hp}/{target_char.max_hp}")
            if target_char.is_defeated():
                log_entries.append(f"  ↳ {target_char.name} 被击败了！")

        elif action_type == "damage":  # 处理普通技能的伤害
            base_power = skill_or_action.get("power", 0)
            spi_bonus_damage = int(attacker.spi * skill_or_action.get("spi_to_damage_ratio", 0.1))
            damage = (attacker.atk + base_power + spi_bonus_damage) - target_char.defe
            damage = max(1, int(damage * random.uniform(0.85, 1.15)))

            target_char.current_hp -= damage
            log_entries.append(
                f"  ↳ 造成 {damage} 点伤害！{target_char.name} 剩余HP: {target_char.current_hp}/{target_char.max_hp}")
            if target_char.is_defeated():
                log_entries.append(f"  ↳ {target_char.name} 被击败了！")

        elif action_type == "buff" or action_type == "debuff":
            actor_to_affect = target_char
            if skill_or_action.get("target") == "self": actor_to_affect = attacker

            stat_changes = skill_or_action.get("stat_changes", {})
            duration = skill_or_action.get("duration", 1)
            applied_effects_desc = []

            effect_data = {
                "type": action_type, "stat_changes": stat_changes,
                "duration": duration + 1, "source_skill": action_name
            }
            actor_to_affect.apply_status_effect(effect_data)

            for stat, change_val in stat_changes.items():
                verb = "提升" if change_val > 0 else "降低"
                applied_effects_desc.append(f"{stat}{verb}{abs(change_val * 100):.0f}%")

            if applied_effects_desc:
                log_entries.append(
                    f"  ↳ {actor_to_affect.name} 的 {', '.join(applied_effects_desc)}，持续 {duration} 回合。")
            if skill_or_action.get("effect_description"):  # 技能特有的额外描述
                log_entries.append(f"  ↳ ({skill_or_action['effect_description']})")

        elif action_type == "heal":
            heal_amount = skill_or_action.get("power", 0)
            spi_bonus_heal = int(attacker.spi * skill_or_action.get("spi_to_heal_ratio", 0.2))
            total_heal = max(1, int((heal_amount + spi_bonus_heal) * random.uniform(0.9, 1.1)))

            actor_to_heal = target_char
            if skill_or_action.get("target") == "self": actor_to_heal = attacker

            actor_to_heal.current_hp = min(actor_to_heal.max_hp, actor_to_heal.current_hp + total_heal)
            log_entries.append(
                f"  ↳ 恢复了 {total_heal} 点HP。【{actor_to_heal.name}】 当前HP: {actor_to_heal.current_hp}/{actor_to_heal.max_hp}")

        # 处理技能的通用 effect_description (如果类型不是以上特定类型，但有描述)
        elif skill_or_action.get("effect_description") and action_type not in ["damage", "buff", "debuff", "heal",
                                                                               "basic_attack"]:
            log_entries.append(f"  ↳ 触发效果：{skill_or_action['effect_description']}")
            if "混乱" in skill_or_action.get("effect_description") or "眩晕" in skill_or_action.get(
                    "effect_description"):
                stun_duration = 1
                try:
                    import re
                    match = re.search(r'(\d+)\s*回合', skill_or_action.get("effect_description"))
                    if match: stun_duration = int(match.group(1))
                except:
                    pass

                target_char.apply_status_effect({
                    "type": "stun", "duration": stun_duration + 1,
                    "source_skill": action_name, "stat_changes": {}
                })
                log_entries.append(f"  ↳ 【{target_char.name}】 陷入了眩晕状态，持续 {stun_duration} 回合！")

        return log_entries

    def advance_turn(self):
        """推进到下一个行动者"""
        # 在推进之前，可以打印一个分隔符，表示上一个角色的行动结束
        # self.response_queue.put(("战场日志", " ", True)) # 一个空行作为视觉分隔，可以按需添加

        self.current_attacker_idx = (self.current_attacker_idx + 1) % len(self.battle_turn_order)

        if not self.check_battle_end():  # 如果战斗未结束
            next_attacker_name = self.battle_turn_order[self.current_attacker_idx]
            next_attacker = self.battle_characters.get(next_attacker_name)

            is_stunned = False
            if next_attacker:  # 确保 next_attacker 对象存在
                for effect in next_attacker.status_effects:
                    if effect.get("type") == "stun":
                        is_stunned = True
                        # 眩晕日志现在更清晰，且独占一行
                        self.response_queue.put(
                            ("战场日志", f"【{next_attacker.name}】 处于眩晕状态，本回合无法行动！", True))
                        effect["duration"] -= 1
                        if effect["duration"] <= 0:
                            # 移除已结束的stun
                            next_attacker.status_effects = [
                                e for e in next_attacker.status_effects
                                if not (e.get("type") == "stun" and e.get("duration") <= 0)
                            ]
                            self.response_queue.put(("战场日志", f"【{next_attacker.name}】 的眩晕效果结束了。", True))
                        break  # 找到一个眩晕就够了

            if is_stunned:
                # 如果眩晕，直接尝试进入下一个人的回合，稍作延迟给用户看日志
                self.root.after(1200, self.advance_turn)
            else:
                # 在下一个角色行动前，输出一个清晰的提示，并稍作停顿
                # 使用 lambda 确保 next_attacker_name 是在 after 调用时正确的值
                self.root.after(1000, lambda name=next_attacker_name: self.response_queue.put(
                    ("战场日志", f"\n轮到 【{name}】 行动...", True)  # 加换行使其更突出
                ))
                # 增加延迟，让提示显示后，再过一段时间才执行实际的回合处理
                self.root.after(2000, self.process_battle_turn)  # 例如总共2秒后执行
        else:
            # 战斗已结束
            self.toggle_ui_state(True)  # 恢复UI交互

    def check_battle_end(self):
        """检查战斗是否结束"""
        if not self.battle_teams or not self.battle_characters:
            return False

        active_members_per_team = {}
        for team_id in self.battle_teams:
            active_members_per_team[team_id] = []

        for char_name, char_obj in self.battle_characters.items():
            # 确保角色属于已知的队伍
            if char_obj.team in active_members_per_team and not char_obj.is_defeated():
                active_members_per_team[char_obj.team].append(char_name)

        living_teams_count = 0
        winner_team_id = None
        for team_id, members in active_members_per_team.items():
            if members:
                living_teams_count += 1
                winner_team_id = team_id

        if living_teams_count <= 1:
            end_message_parts = ["\n！！！战斗结束！！！"]  # 开头加换行
            if winner_team_id and living_teams_count == 1:
                winner_members_names = self.battle_teams.get(winner_team_id, [])
                # 获取角色对象以显示最终状态
                winner_char_details = []
                for name in winner_members_names:
                    char = self.battle_characters.get(name)
                    if char:  # 确保角色存在
                        winner_char_details.append(f"{name} ({char.current_hp}/{char.max_hp} HP)")

                end_message_parts.append(f"队伍 {winner_team_id} ({', '.join(winner_char_details)}) 获得了胜利！")
            elif living_teams_count == 0:
                end_message_parts.append("所有人都被击败了，真是惨烈的平局...")
            else:
                end_message_parts.append("（出现意外的结束条件）")

            self.response_queue.put(("战场日志", "\n".join(end_message_parts), True))  # True 确保整块信息后有大换行
            self.response_queue.put(("SYSTEM_PHASE_UPDATE", "battle_over"))
            return True
        return False


# --- 程序入口 ---
if __name__ == "__main__":
    root = tk.Tk()
    app = TextBattleArenaApp(root)
    root.mainloop()